package org.simpleframework.inject;

import lombok.extern.slf4j.Slf4j;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.inject.annotation.AutoWired;
import org.simpleframework.util.ClassUtil;
import org.simpleframework.util.ValidationUtil;

import java.lang.reflect.Field;
import java.util.Set;

@Slf4j
public class DependencyInjector {
    /**
     * Bean容器
     */
    private BeanContainer beanContainer;

    public DependencyInjector() {
        this.beanContainer = BeanContainer.getInstance();
    }

    /**
     * 执行IOC
     */
    public void doIoc(){
        //1.遍历Bean容器中所有的Class对象
        if(ValidationUtil.isEmpty(beanContainer.getClasses())){
            log.warn("empty classSet in BeanContainer");
            return;
        }
        for (Class<?> clazz : beanContainer.getClasses()) {
            //2.遍历Class对象的所有成员变量
            Field[] fields = clazz.getDeclaredFields();
            if(ValidationUtil.isEmpty(fields)){
                continue;
            }
            for (Field field : fields) {
                //3.找出被AutoWired标记的成员变量
                if(field.isAnnotationPresent(AutoWired.class)){
                    AutoWired autoWired=field.getAnnotation(AutoWired.class);
                    String autoWiredValue = autoWired.value();
                    //4.获取这些成员变量的类型
                   Class<?> fieldClass=field.getType();
                    //5.获取这些成员变量的类型在IOC容器中对应的实例
                   Object fieldValue=  getFieldInstance(fieldClass,autoWiredValue);
                   if(fieldValue==null){
                       throw new RuntimeException("unable to inject relevant type,target fieldClass is"+fieldClass.getName()+autoWiredValue);
                   }else{
                       //6.通过反射将对应的成员变量实例注入到成员变量所在类的实例中
                       Object targetBean = beanContainer.getBean(clazz);
                       ClassUtil.setField(field,targetBean,fieldValue,true);
                   }
                }
            }

        }


    }

    /**
     * 根据Class对象在beanContainer里获取实例或者实现类
     * @param fieldClass
     * @return
     */
    private Object getFieldInstance(Class<?> fieldClass,String autoWiredValue) {
        Object fieldValue = beanContainer.getBean(fieldClass);
        if(fieldValue!=null){
            return fieldValue;
        }else {
           Class<?> implementClass= getImplementClass(fieldClass,autoWiredValue);
           if(implementClass!=null){
               return beanContainer.getBean(implementClass);
            }else {
               return null;
           }
        }
    }

    /**
     * 获取接口的实现类
     * @param fieldClass
     * @return
     */
    private Class<?> getImplementClass(Class<?> fieldClass,String autoWiredValue) {
        Set<Class<?>> classSet = beanContainer.getClassBySuper(fieldClass);
        if (!ValidationUtil.isEmpty(classSet)) {
                if(ValidationUtil.isEmpty(autoWiredValue)){
                    if(classSet.size()==1){
                        return classSet.iterator().next();
                    }else{
                        //如果多于两个实现类且用户未指定其中一个实现类，则抛出异常
                        throw new RuntimeException("multiple implemented classes for"+fieldClass.getName()+"please set @AutoWired value to pick one");
                    }
                }else {
                    for (Class<?> clazz : classSet) {
                        if(autoWiredValue.equals(clazz.getSimpleName())){
                            return  clazz;
                    }
                }
          }
         }
        return null;
    }
}
